#region Microsoft Public License
/*
 * (c) Copyright Chenjun Wu. http://utablesdk.codeplex.com
 * 
 * This source is subject to the Microsoft Public License (Ms-PL).
 * Please see http://go.microsoft.com/fwlink/?LinkID=131993 for details.
 * All other rights reserved.
 */
#endregion

﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Windows;
using System.Windows.Controls;
using UTable.Input;
using UTable.Input.MultiTouch;
using UTable.Objects;
using UTable.Objects.Controls;
using System.IO;
using System.Windows.Media;
using System.Collections.ObjectModel;
using System.Reflection;
using System.Windows.Media.Imaging;
using UTable.ObjectManager.Commands;

namespace UTable.Objects
{
    /// <summary>
    /// Interaction logic for UAppLoader.xaml
    /// </summary>
    public partial class UAppLoader : UObject
    {
        List<String> _apps = new List<string>();
        List<UButton> _appButtons = new List<UButton>();
        public ObservableCollection<UApplicationAbstract> _applications = new ObservableCollection<UApplicationAbstract>();

        public ObservableCollection<UApplicationAbstract> Applications
        {
            get { return _applications; }
        }

        public UAppLoader()
        {
            InitializeComponent();
            Fresh();
            this.DataContext = this;
        }

        /// <summary>
        /// Fresh the applications
        /// </summary>
        public void Fresh()
        {
            Applications.Clear();
            LoadAppsFromDirectory("Apps", Applications);
        }

        public static void LoadApplication(String directory, Point position, double orientation, IObject owner)
        {
            Collection<UApplicationAbstract> applications = new Collection<UApplicationAbstract>();
            LoadApplication(directory, applications);
            if (applications.Count == 0)
                return;
            UApplicationAbstract appAbstract = applications[0];

            ObjectCreateParameter appParam = new ObjectCreateParameter(appAbstract.MainObjectType);
            IObject app = UTableHelper.CreateObject(appParam);
            app.Position = position;
            app.Orientation = orientation;
            app.Owner = owner;
        }

        public static void LoadAppsFromDirectory(string directoryPath, Collection<UApplicationAbstract> applications)
        {
            if (!Directory.Exists("Apps"))
            {
                Logger.ULogger.Error("The \"Apps\" folder is not found. Cannot load applications.");
                return;
            }

            String[] directories = Directory.GetDirectories(directoryPath);
            
            foreach (String directory in directories)
            {
                if (Directory.Exists(directory) && Path.GetFileName(directory) != ".svn")
                {
                    LoadApplication(directory, applications);
                }
            }
        }

        public static void LoadApplication(string directoryPath, Collection<UApplicationAbstract> applications)
        {
            // load the icon for the application
            String[] files = Directory.GetFiles(directoryPath);
            ImageSource icon = null;
            foreach (String file in files)
            {
                if (File.Exists(file) && (file.EndsWith("icon.jpg") || file.EndsWith("icon.png")))
                {
                    icon = new BitmapImage(new Uri(Path.GetFullPath(file), UriKind.Absolute));
                }
            }

            // load the application
            UApplicationAbstract app = null;
            //AppDomainSetup appSetup = new AppDomainSetup();
            //appSetup.ApplicationBase = Path.GetFullPath(directoryPath);
            //appSetup.PrivateBinPath = "bin";
            //System.Security.PermissionSet perSet = new System.Security.PermissionSet(System.Security.Permissions.PermissionState.Unrestricted);
            //AppDomain domain = AppDomain.CreateDomain(directoryPath, null, appSetup, perSet);
            foreach (String file in files)
            {
                if (File.Exists(file))
                {
                    app = GetApplicationAbstract(file);
                    if (app != null)
                    {
                        applications.Add(app);
                        app.Icon = icon;
                        break;
                    }
                }
            }
        }

        public static UApplicationAbstract GetApplicationAbstract(String assemblyPath)
        {
            try
            {
                Assembly assembly = Assembly.LoadFrom(assemblyPath);
                // Assembly assembly = domain.Load(AssemblyName.GetAssemblyName(assemblyPath));
                // Find the object in this assembly
                Type[] types = assembly.GetTypes();
                Type objectType = null;
                foreach (Type type in types)
                {
                    if (type.IsSubclassOf(typeof(UObject)))
                    {
                        object[] attributes = type.GetCustomAttributes(false);
                        foreach (object o in attributes)
                        {
                            if (o is MainObjectAttribute)
                            {
                                UApplicationAbstract app = new UApplicationAbstract();
                                app.MainObjectType = type;
                                foreach (object a in attributes)
                                {
                                    if (a is LoadTitleAttribute)
                                    {
                                        app.Title = (a as LoadTitleAttribute).Title;
                                    }
                                    if (a is LoadIconAttribute)
                                    {
                                        // app.Icon = (a as LoadIconAttribute).Icon;
                                    }
                                }
                                return app;
                            }
                        }
                        objectType = type;
                    }
                }
            }
            catch (System.Exception e)
            {
                return null;
            }
            return null;
        }

        public void CreateApp(Type appType)
        {
            // UTableHelper.PutCommand(new ObjectCommand(this, ObjectCommandType.Insert, obj));
            ObjectCreateParameter appParam = new ObjectCreateParameter(appType);
            IObject app = UTableHelper.CreateObject(appParam);
            IObject owner = this.Owner;
            
            // place the application at the same center with the app loader
            Point expectedPosition = new Point(this.Position.X + this.Width / 2 - app.Width / 2, this.Position.Y + this.Height / 2 - app.Height / 2);
            if (expectedPosition.X < 0)
                expectedPosition.X = 0;
            else if (expectedPosition.X + app.Width > owner.Width)
                expectedPosition.X = owner.Width - app.Width;
            if (expectedPosition.Y < 0)
                expectedPosition.Y = 0;
            else if (expectedPosition.Y + app.Height > owner.Height)
                expectedPosition.Y = owner.Height - app.Height;
            app.Position = expectedPosition;

            // the orientation of the app should be the same with the app loader
            double orientation = (this.Orientation % 360 + 360) % 360;
            if (orientation > 135 && orientation < 225)
                app.Orientation = 180;
            else if (orientation > 50 && orientation < 135)
                app.Orientation = 90;
            else if (orientation > 225 && orientation < 310)
                app.Orientation = 270;

            app.Owner = owner;
            this.Close();
        }

        private void UButton_Pressed(object sender, ButtonEventArgs args)
        {
            UApplicationAbstract app = (sender as UButton).DataContext as UApplicationAbstract;
            CreateApp(app.MainObjectType);
        }

    }

    public class UApplicationAbstract: DependencyObject
    {
        public String Title
        {
            get { return (String)GetValue(TitleProperty); }
            set { SetValue(TitleProperty, value); }
        }

        public static readonly DependencyProperty TitleProperty =
            DependencyProperty.Register("Title", typeof(String), typeof(UApplicationAbstract), new UIPropertyMetadata("UApplication"));


        public ImageSource Icon
        {
            get { return (ImageSource)GetValue(IconProperty); }
            set { SetValue(IconProperty, value); }
        }

        public static readonly DependencyProperty IconProperty =
            DependencyProperty.Register("Icon", typeof(ImageSource), typeof(UApplicationAbstract), new UIPropertyMetadata(new BitmapImage(new Uri("\\Images\\icon1.png", UriKind.Relative))));

        public Type MainObjectType
        {
            get { return (Type)GetValue(MainObjectTypeProperty); }
            set { SetValue(MainObjectTypeProperty, value); }
        }

        public static readonly DependencyProperty MainObjectTypeProperty =
            DependencyProperty.Register("MainObjectType", typeof(Type), typeof(UApplicationAbstract), new UIPropertyMetadata(null));
    }
}
